package global

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync"
	"git.oschina.net/YPTArch/basic/models"
	"git.oschina.net/YPTArch/km_api_dispatcher/sys/logs"
)

//api ...
type api struct {
	method  string
	auth    string
	cmdList []*cmd
}

type cmd struct {
	ID                string
	Name              string
	OrderCode         int
	Type1             string
	Type2             string
	Type3             string
	Template          string
	ContinueStateList []int64
	ParamList         []*param
}

type param struct {
	Type     string
	Name     string
	DataType string
}

var apiList = &struct {
	apiMap map[string]*api
	l      *sync.Mutex
}{l: new(sync.Mutex)}

//Handle ...
func (a *api) Handle(params map[string]interface{}) models.Result {
	apiList.l.Lock()         //apiList上锁
	defer apiList.l.Unlock() //apiList解锁
	// if a.auth == "1" {       //需要鉴权
	// 	vtAPI := getAPI("verifytoken", "POST")
	// 	if vtAPI == nil {
	// 		Log.Info("Invalid API verifytoken 但是继续运行，因为说这个不在通用微服务中了，所以暂时输出一个这个信息")
	// 		//return models.Result{Code: 401, Msg: "Invalid API verifytoken"}
	// 		return dbDriver.BeginTrans(a.cmdList, params)
	// 	}

	// 	verifyTokenResult := dbDriver.BeginTrans(vtAPI.cmdList, params)
	// 	if verifyTokenResult.Code == 200 {
	// 		verifyTokenResultData := verifyTokenResult.Data.(map[string]interface{})["verifytoken"].(map[string]interface{})
	// 		if vtrState, vtrStateExisted := verifyTokenResultData["state"]; vtrStateExisted && vtrState.(string) == "0" {
	// 			for k, v := range verifyTokenResultData {
	// 				params[k] = v
	// 			}
	// 			return dbDriver.BeginTrans(a.cmdList, params)
	// 		}
	// 	}

	// 	return models.Result{Code: 401, Msg: "身份验证失败，请重新登录"}
	// }
	return dbDriver.BeginTrans(a.cmdList, params)
}

func updateAPIList() {
		u, _ := url.Parse(fmt.Sprintf("http://%s/api/get_apilist_detail", Conf.KM.URL))
		q := u.Query()
		data := make(map[string]interface{})
		data["app_appid"] = Conf.App.AppID
		data["app_appkey"] = Conf.App.AppKey
		data["ms_name"] = Conf.Service.Name
		bs, _ := json.Marshal(data)
		q.Set("data", coder.EncodeToString(bs))
		u.RawQuery = q.Encode()
		uu := u.String()
		res, err := http.Get(uu)
		if err != nil {
			logs.Logger.Error("GetApiList failed : " + u.String() + " ERR: " + err.Error())
		}
		body, err := ioutil.ReadAll(res.Body)
		defer res.Body.Close()
		if err != nil {
			logs.Logger.Error("GetApiList failed : Read response : " + u.String())
		}
		var result models.Result
		json.Unmarshal(body, &result)

		apiList.l.Lock() //上锁
		if apiList.apiMap != nil {
			for k := range apiList.apiMap {
				delete(apiList.apiMap, k)
			}
		} else {
			apiList.apiMap = make(map[string]*api)
		}

		if result.Code == 200 {
			resultData := result.Data.(map[string]interface{})
			//遍历加载API列表
			if resultData["apilist"] != nil {
				for _, resultAPIList := range resultData["apilist"].([]interface{}) {
					apiList.apiMap[resultAPIList.(map[string]interface{})["api_name"].(string)] = &api{
						method: strings.ToUpper(resultAPIList.(map[string]interface{})["api_method"].(string)),
						auth:   resultAPIList.(map[string]interface{})["api_auth"].(string)}
				}
			}
			//遍历加载命令列表
			if resultData["apicmdlist"] != nil {
				for _, resultAPICMDList := range resultData["apicmdlist"].([]interface{}) {
					a, aExisted := apiList.apiMap[resultAPICMDList.(map[string]interface{})["api_name"].(string)]
					if aExisted {
						ac := &cmd{
							ID:   resultAPICMDList.(map[string]interface{})["apic_id"].(string),
							Name: resultAPICMDList.(map[string]interface{})["apic_name"].(string),
							OrderCode: func() (oc int) {
								oc, _ = strconv.Atoi(resultAPICMDList.(map[string]interface{})["apic_ordercode"].(string))
								return oc
							}(),
							Type1: resultAPICMDList.(map[string]interface{})["apic_type1"].(string),
							Type2: resultAPICMDList.(map[string]interface{})["apic_type2"].(string),
							Type3: resultAPICMDList.(map[string]interface{})["apic_type3"].(string),
							ContinueStateList: func() (csl []int64) {
								ss := strings.Split(resultAPICMDList.(map[string]interface{})["apic_continuestate"].(string), ",")
								for _, s := range ss {
									if s != "" {
										cs, _ := strconv.ParseInt(s, 10, 64)
										csl = append(csl, cs)
									}
								}
								return csl
							}(),
							Template: resultAPICMDList.(map[string]interface{})["apic_template"].(string)}
						j := 0
						for ; j < len(a.cmdList); j++ {
							if ac.OrderCode < a.cmdList[j].OrderCode {
								break
							}
						}
						tmp := append([]*cmd{}, a.cmdList[j:]...)
						a.cmdList = append(a.cmdList[0:j], ac)
						a.cmdList = append(a.cmdList, tmp...)
					}
				}
			}
			//遍历加载参数列表
			if resultData["apicmdparamlist"] != nil {
				for _, resultAPICMDParamList := range resultData["apicmdparamlist"].([]interface{}) {
					a, aExisted := apiList.apiMap[resultAPICMDParamList.(map[string]interface{})["api_name"].(string)]
					if aExisted {
						var ac *cmd
						for _, cmd := range a.cmdList {
							if cmd.ID == resultAPICMDParamList.(map[string]interface{})["apic_id"].(string) {
								ac = cmd
							}
						}
						if ac != nil {
							ac.ParamList = append(
								ac.ParamList,
								&param{
									Type:     resultAPICMDParamList.(map[string]interface{})["apicp_type"].(string),
									Name:     resultAPICMDParamList.(map[string]interface{})["apicp_name"].(string),
									DataType: resultAPICMDParamList.(map[string]interface{})["apicp_datatype"].(string)})
						}
					}
				}
			}
			apiList.l.Unlock() //解锁
			var apicQty, apicpQty int
			for _, a := range apiList.apiMap {
				apicQty += len(a.cmdList)
				for _, ac := range a.cmdList {
					apicpQty += len(ac.ParamList)
				}
			}
			logs.Logger.Info("Update " + strconv.Itoa(len(apiList.apiMap)) + " API ; Update " + strconv.Itoa(apicQty) + " API CMD ; Update " + strconv.Itoa(apicpQty) + " API CMD Param")
		} else {
			logs.Logger.Error(result.Msg)
		}
	Reg()
}

//getAPI ...
func getAPI(apiName string, apiMethod string) *api {
	a, apiExisted := apiList.apiMap[apiName]
	if apiExisted && a.method == apiMethod {
		return a
	}
	return nil
}

//APIHandle ...
func APIHandle(w http.ResponseWriter, r *http.Request) {
	defer func() {
		if err := recover(); err != nil {
			logs.Logger.Error("Error from [mysql.go] APIHandle() -> " + err.(error).Error())
			// return models.Result{Code: 500, Msg: "API处理异常"}
		}
	}()

	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Headers, Authorization")
	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
	w.Header().Set("Content-Type", "application/json")

	pathSplit := strings.Split(r.URL.Path, "/")
	if len(pathSplit) > 2 {
		apiName := pathSplit[2]
		apiMethod := r.Method
		params := make(map[string]interface{})
		r.ParseForm()
		for k, v := range r.Form {
			// params[k] = v[0]
			params[k] = v
		}
		if data, dataExisted := r.Form["data"]; dataExisted && len(data) > 0 {
			ds, _ := coder.DecodeString(strings.Replace(data[0], " ", "+", -1))
			json.Unmarshal(ds, &params)
		}
		//从Header中取得Token
		if token, headerTokenExsited := r.Header["Authorization"]; headerTokenExsited {
			params["token"] = token
		}
		if a := getAPI(apiName, apiMethod); a != nil {
			// Log.Info("Request API " + apiName + " [" + apiMethod + "]")
			apiResultJSONData, _ := json.Marshal(a.Handle(params))
			w.Write(apiResultJSONData)
			return
		}
		msg := "Invalid API " + apiName + " [" + apiMethod + "]"
		// Log.Info(msg)
		errJSON, _ := json.Marshal(models.Result{Code: 404, Msg: msg})
		w.Write(errJSON)
	}
}
